////////////////////////////////////////////////////////////////
//                                                            //
//  Neoforce Controls                                         //
//                                                            //
////////////////////////////////////////////////////////////////
//                                                            //
//         File: Renderer.cs                                  //
//                                                            //
//      Version: 0.7                                          //
//                                                            //
//         Date: 11/09/2010                                   //
//                                                            //
//       Author: Tom Shane                                    //
//                                                            //
////////////////////////////////////////////////////////////////
//                                                            //
//  Copyright (c) by Tom Shane                                //
//                                                            //
////////////////////////////////////////////////////////////////

#region //// Using /////////////

////////////////////////////////////////////////////////////////////////////
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
////////////////////////////////////////////////////////////////////////////

#endregion

namespace TomShane.Neoforce.Controls
{
  public enum BlendingMode
  {    
    Default,
    None,
  }

  #region //// Classes ///////////

  ////////////////////////////////////////////////////////////////////////////
  public class DeviceStates
  {
    public readonly BlendState BlendState;    
    public readonly RasterizerState RasterizerState;
    public readonly DepthStencilState DepthStencilState;
    public readonly SamplerState SamplerState;

    public DeviceStates()
    {      
      BlendState = new BlendState();      
      BlendState.AlphaBlendFunction = BlendState.AlphaBlend.AlphaBlendFunction;
      BlendState.AlphaDestinationBlend = BlendState.AlphaBlend.AlphaDestinationBlend;
      BlendState.AlphaSourceBlend = BlendState.AlphaBlend.AlphaSourceBlend;
      BlendState.BlendFactor = BlendState.AlphaBlend.BlendFactor;
      BlendState.ColorBlendFunction = BlendState.AlphaBlend.ColorBlendFunction;
      BlendState.ColorDestinationBlend = BlendState.AlphaBlend.ColorDestinationBlend;
      BlendState.ColorSourceBlend = BlendState.AlphaBlend.ColorSourceBlend;
      BlendState.ColorWriteChannels = BlendState.AlphaBlend.ColorWriteChannels;
      BlendState.ColorWriteChannels1 = BlendState.AlphaBlend.ColorWriteChannels1;
      BlendState.ColorWriteChannels2 = BlendState.AlphaBlend.ColorWriteChannels2;
      BlendState.ColorWriteChannels3 = BlendState.AlphaBlend.ColorWriteChannels3;
      BlendState.MultiSampleMask = BlendState.AlphaBlend.MultiSampleMask;     
      
      RasterizerState = new RasterizerState();            
      RasterizerState.CullMode = RasterizerState.CullNone.CullMode;
      RasterizerState.DepthBias = RasterizerState.CullNone.DepthBias;
      RasterizerState.FillMode = RasterizerState.CullNone.FillMode;
      RasterizerState.MultiSampleAntiAlias = RasterizerState.CullNone.MultiSampleAntiAlias;
      RasterizerState.ScissorTestEnable = RasterizerState.CullNone.ScissorTestEnable;
      RasterizerState.SlopeScaleDepthBias = RasterizerState.CullNone.SlopeScaleDepthBias;

      RasterizerState.ScissorTestEnable = true;
      
      SamplerState = new SamplerState();
      SamplerState.AddressU = SamplerState.AnisotropicClamp.AddressU;
      SamplerState.AddressV = SamplerState.AnisotropicClamp.AddressV;
      SamplerState.AddressW = SamplerState.AnisotropicClamp.AddressW;
      SamplerState.Filter = SamplerState.AnisotropicClamp.Filter;
      SamplerState.MaxAnisotropy = SamplerState.AnisotropicClamp.MaxAnisotropy;
      SamplerState.MaxMipLevel = SamplerState.AnisotropicClamp.MaxMipLevel;
      SamplerState.MipMapLevelOfDetailBias = SamplerState.AnisotropicClamp.MipMapLevelOfDetailBias;
      
      DepthStencilState = new DepthStencilState();
      DepthStencilState = DepthStencilState.None;
    }
  }
  ////////////////////////////////////////////////////////////////////////////

  #endregion  
  
  public class Renderer: Component
  {   

    #region //// Fields ////////////

    ////////////////////////////////////////////////////////////////////////////
    private SpriteBatch sb = null;  
    private DeviceStates states = new DeviceStates();           
    ////////////////////////////////////////////////////////////////////////////

    #endregion

    #region //// Properties ////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual SpriteBatch SpriteBatch
    {
      get
      {
        return sb;
      }
    }
    ////////////////////////////////////////////////////////////////////////////

    #endregion    

    #region //// Constructors //////

    ////////////////////////////////////////////////////////////////////////////
    public Renderer(Manager manager): base(manager)
    {
      sb = new SpriteBatch(Manager.GraphicsDevice);
    }
    ////////////////////////////////////////////////////////////////////////////

    #endregion

    #region //// Destructors ///////

    ////////////////////////////////////////////////////////////////////////////
    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        if (sb != null)
        {
          sb.Dispose();
          sb = null;
        }  
      }
      base.Dispose(disposing);
    }
    ////////////////////////////////////////////////////////////////////////////

    #endregion    
    
    #region //// Methods ///////////

    ////////////////////////////////////////////////////////////////////////////
    public override void Init()
    {
      base.Init();      
    }
    ////////////////////////////////////////////////////////////////////////////
    
    ////////////////////////////////////////////////////////////////////////////
    public virtual void Begin(BlendingMode mode)
    {                                    
      if (mode != BlendingMode.None)
      {        
        sb.Begin(SpriteSortMode.Immediate, states.BlendState, states.SamplerState, states.DepthStencilState, states.RasterizerState);                
      }
      else
      {
        sb.Begin(SpriteSortMode.Immediate, BlendState.Opaque, states.SamplerState, states.DepthStencilState, states.RasterizerState);
      }              
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void End()
    {      
      sb.End();            
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void Draw(Texture2D texture, Rectangle destination, Color color)
    {      
      if (destination.Width > 0 && destination.Height > 0)
      {       
        sb.Draw(texture, destination, null, color, 0.0f, Vector2.Zero, SpriteEffects.None, Manager.GlobalDepth);
      }  
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void Draw(Texture2D texture, Rectangle destination, Rectangle source, Color color)
    {      
      if (source.Width > 0 && source.Height > 0 && destination.Width > 0 && destination.Height > 0)
      {        
        sb.Draw(texture, destination, source, color, 0.0f, Vector2.Zero, SpriteEffects.None, Manager.GlobalDepth);
      }  
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void Draw(Texture2D texture, int left, int top, Color color)
    {
      sb.Draw(texture, new Vector2(left, top), null, color, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, Manager.GlobalDepth);
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void Draw(Texture2D texture, int left, int top, Rectangle source, Color color)
    {      
      if (source.Width > 0 && source.Height > 0)
      {        
        sb.Draw(texture, new Vector2(left, top), source, color, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, Manager.GlobalDepth);
      }
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(SpriteFont font, string text, int left, int top, Color color)
    {                            
      sb.DrawString(font, text, new Vector2(left, top), color, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, Manager.GlobalDepth);      
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(SpriteFont font, string text, Rectangle rect, Color color, Alignment alignment)
    {      
      DrawString(font, text, rect, color, alignment, 0, 0, true);
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(SpriteFont font, string text, Rectangle rect, Color color, Alignment alignment, bool ellipsis)
    {
      DrawString(font, text, rect, color, alignment, 0, 0, ellipsis);
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(Control control, SkinLayer layer, string text, Rectangle rect)
    {
      DrawString(control, layer, text, rect, true, 0, 0, true);
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(Control control, SkinLayer layer, string text, Rectangle rect, ControlState state)
    {
      DrawString(control, layer, text, rect, state, true, 0, 0, true);
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(Control control, SkinLayer layer, string text, Rectangle rect, bool margins)
    {
      DrawString(control, layer, text, rect, margins, 0, 0, true);
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(Control control, SkinLayer layer, string text, Rectangle rect, ControlState state, bool margins)
    {
      DrawString(control, layer, text, rect, state, margins, 0, 0, true);
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(Control control, SkinLayer layer, string text, Rectangle rect, bool margins, int ox, int oy)
    {
      DrawString(control, layer, text, rect, margins, ox, oy, true);
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(Control control, SkinLayer layer, string text, Rectangle rect, ControlState state, bool margins, int ox, int oy)
    {
      DrawString(control, layer, text, rect, state, margins, ox, oy, true);
    }
    ////////////////////////////////////////////////////////////////////////////
       
    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(Control control, SkinLayer layer, string text, Rectangle rect, bool margins, int ox, int oy, bool ellipsis)
    {     
      DrawString(control, layer, text, rect, control.ControlState, margins, ox, oy, ellipsis);      
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(Control control, SkinLayer layer, string text, Rectangle rect, ControlState state, bool margins, int ox, int oy, bool ellipsis)
    {
      Color col = Color.White;

      if (layer.Text != null)
      {
        if (margins)
        {
          Margins m = layer.ContentMargins;
          rect = new Rectangle(rect.Left + m.Left, rect.Top + m.Top, rect.Width - m.Horizontal, rect.Height - m.Vertical);
        }

        if (state == ControlState.Hovered && (layer.States.Hovered.Index != -1))
        {
          col = layer.Text.Colors.Hovered;
        }
        else if (state == ControlState.Pressed)
        {
          col = layer.Text.Colors.Pressed;
        }
        else if (state == ControlState.Focused || (control.Focused && state == ControlState.Hovered && layer.States.Hovered.Index == -1))
        {
          col = layer.Text.Colors.Focused;
        }
        else if (state == ControlState.Disabled)
        {
          col = layer.Text.Colors.Disabled;
        }
        else
        {
          col = layer.Text.Colors.Enabled;
        }

        if (text != null && text != "")
        {
          SkinText font = layer.Text;
          if (control.TextColor != Control.UndefinedColor && control.ControlState != ControlState.Disabled) col = control.TextColor;
          DrawString(font.Font.Resource, text, rect, col, font.Alignment, font.OffsetX + ox, font.OffsetY + oy, ellipsis);
        }
      }
    }
    ////////////////////////////////////////////////////////////////////////////
    
    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawString(SpriteFont font, string text, Rectangle rect, Color color, Alignment alignment, int offsetX, int offsetY, bool ellipsis)
    {      
    
      if (ellipsis)
      {
        const string elli = "...";
        int size = (int)Math.Ceiling(font.MeasureString(text).X);
        if (size > rect.Width)
        {
          int es = (int)Math.Ceiling(font.MeasureString(elli).X);
          for (int i = text.Length - 1; i > 0; i--)
          {                        
            int c = 1;
            if (char.IsWhiteSpace(text[i - 1]))
            {
              c = 2;
              i--;        
            }                        
            text = text.Remove(i, c);
            size = (int)Math.Ceiling(font.MeasureString(text).X);
            if (size + es <= rect.Width)
            {              
              break;
            }  
          }
          text += elli;
        }
      }
    
      if (rect.Width > 0 && rect.Height > 0)
      {                                        
        Vector2 pos = new Vector2(rect.Left, rect.Top);
        Vector2 size = font.MeasureString(text);

        int x = 0; int y = 0;

        switch (alignment)
        {
          case Alignment.TopLeft:          
          break;        
          case Alignment.TopCenter:
            x = GetTextCenter(rect.Width, size.X);
          break;
          case Alignment.TopRight:
            x = rect.Width - (int)size.X;
          break;
          case Alignment.MiddleLeft:
            y = GetTextCenter(rect.Height, size.Y);
          break;
          case Alignment.MiddleRight:
            x = rect.Width - (int)size.X;
            y = GetTextCenter(rect.Height, size.Y);
          break;
          case Alignment.BottomLeft:
            y = rect.Height - (int)size.Y;
          break;
          case Alignment.BottomCenter:
            x = GetTextCenter(rect.Width, size.X);
            y = rect.Height - (int)size.Y;
          break;
          case Alignment.BottomRight:
            x = rect.Width - (int)size.X;
            y = rect.Height - (int)size.Y;
          break;
          
          default:
            x = GetTextCenter(rect.Width, size.X);
            y = GetTextCenter(rect.Height, size.Y);
          break;
        }

        pos.X = (int)(pos.X + x);
        pos.Y = (int)(pos.Y + y);

        DrawString(font, text, (int)pos.X + offsetX, (int)pos.Y + offsetY, color);
      }      
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    private static int GetTextCenter(float size1, float size2)
    {
      return (int)Math.Ceiling((size1 / 2) - (size2 / 2));
    }
    ////////////////////////////////////////////////////////////////////////////              

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawLayer(SkinLayer layer, Rectangle rect, Color color, int index)
    {
      Size imageSize = new Size(layer.Image.Resource.Width, layer.Image.Resource.Height);
      Size partSize = new Size(layer.Width, layer.Height);

      Draw(layer.Image.Resource, GetDestinationArea(rect, layer.SizingMargins, Alignment.TopLeft), GetSourceArea(imageSize, partSize, layer.SizingMargins, Alignment.TopLeft, index), color);
      Draw(layer.Image.Resource, GetDestinationArea(rect, layer.SizingMargins, Alignment.TopCenter), GetSourceArea(imageSize, partSize, layer.SizingMargins, Alignment.TopCenter, index), color);          
      Draw(layer.Image.Resource, GetDestinationArea(rect, layer.SizingMargins, Alignment.TopRight), GetSourceArea(imageSize, partSize, layer.SizingMargins, Alignment.TopRight, index), color);            
      Draw(layer.Image.Resource, GetDestinationArea(rect, layer.SizingMargins, Alignment.MiddleLeft), GetSourceArea(imageSize, partSize, layer.SizingMargins, Alignment.MiddleLeft, index), color);                  
      Draw(layer.Image.Resource, GetDestinationArea(rect, layer.SizingMargins, Alignment.MiddleCenter), GetSourceArea(imageSize, partSize, layer.SizingMargins, Alignment.MiddleCenter, index), color);
      Draw(layer.Image.Resource, GetDestinationArea(rect, layer.SizingMargins, Alignment.MiddleRight), GetSourceArea(imageSize, partSize, layer.SizingMargins, Alignment.MiddleRight, index), color);
      Draw(layer.Image.Resource, GetDestinationArea(rect, layer.SizingMargins, Alignment.BottomLeft), GetSourceArea(imageSize, partSize, layer.SizingMargins, Alignment.BottomLeft, index), color);
      Draw(layer.Image.Resource, GetDestinationArea(rect, layer.SizingMargins, Alignment.BottomCenter), GetSourceArea(imageSize, partSize, layer.SizingMargins, Alignment.BottomCenter, index), color);
      Draw(layer.Image.Resource, GetDestinationArea(rect, layer.SizingMargins, Alignment.BottomRight), GetSourceArea(imageSize, partSize, layer.SizingMargins, Alignment.BottomRight, index), color);                  
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    private static Rectangle GetSourceArea(Size imageSize, Size partSize, Margins margins, Alignment alignment, int index)
    {
      Rectangle rect = new Rectangle();
      int xc = (int)((float)imageSize.Width / partSize.Width);
      int yc = (int)((float)imageSize.Height / partSize.Height);

      int xm = (index) % xc;
      int ym = (index) / xc;

      int adj = 1;
      margins.Left += margins.Left > 0 ? adj : 0;
      margins.Top += margins.Top > 0 ? adj : 0;
      margins.Right += margins.Right > 0 ? adj : 0;
      margins.Bottom += margins.Bottom > 0 ? adj : 0;

      margins = new Margins(margins.Left, margins.Top, margins.Right, margins.Bottom);
      switch (alignment)
      {
        case Alignment.TopLeft:
        {
          rect = new Rectangle((0 + (xm * partSize.Width)),
                               (0 + (ym * partSize.Height)),
                               margins.Left,
                               margins.Top);
          break;
        }
        case Alignment.TopCenter:
        {
          rect = new Rectangle((0 + (xm * partSize.Width)) + margins.Left,
                               (0 + (ym * partSize.Height)),
                               partSize.Width - margins.Left - margins.Right,
                               margins.Top);
          break;
        }
        case Alignment.TopRight:
        {
          rect = new Rectangle((partSize.Width + (xm * partSize.Width)) - margins.Right,
                               (0 + (ym * partSize.Height)),
                               margins.Right,
                               margins.Top);
          break;
        }
        case Alignment.MiddleLeft:
        {
          rect = new Rectangle((0 + (xm * partSize.Width)),
                               (0 + (ym * partSize.Height)) + margins.Top,
                               margins.Left,
                               partSize.Height - margins.Top - margins.Bottom);
          break;
        }
        case Alignment.MiddleCenter:
        {
          rect = new Rectangle((0 + (xm * partSize.Width)) + margins.Left,
                               (0 + (ym * partSize.Height)) + margins.Top,
                               partSize.Width - margins.Left - margins.Right,
                               partSize.Height - margins.Top - margins.Bottom);
          break;
        }
        case Alignment.MiddleRight:
        {
          rect = new Rectangle((partSize.Width + (xm * partSize.Width)) - margins.Right,
                               (0 + (ym * partSize.Height)) + margins.Top,
                               margins.Right,
                               partSize.Height - margins.Top - margins.Bottom);
          break;
        }
        case Alignment.BottomLeft:
        {
          rect = new Rectangle((0 + (xm * partSize.Width)),
                               (partSize.Height + (ym * partSize.Height)) - margins.Bottom,
                               margins.Left,
                               margins.Bottom);
          break;
        }
        case Alignment.BottomCenter:
        {
          rect = new Rectangle((0 + (xm * partSize.Width)) + margins.Left,
                               (partSize.Height + (ym * partSize.Height)) - margins.Bottom,
                               partSize.Width - margins.Left - margins.Right,
                               margins.Bottom);
          break;
        }
        case Alignment.BottomRight:
        {
          rect = new Rectangle((partSize.Width + (xm * partSize.Width)) - margins.Right,
                               (partSize.Height + (ym * partSize.Height)) - margins.Bottom,
                               margins.Right,
                               margins.Bottom);
          break;
        }
      }

      return rect;
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public static Rectangle GetDestinationArea(Rectangle area, Margins margins, Alignment alignment)
    {
      Rectangle rect = new Rectangle();
      
      int adj = 1;      
      margins.Left += margins.Left > 0 ? adj : 0;
      margins.Top += margins.Top > 0 ? adj : 0;
      margins.Right += margins.Right > 0 ? adj : 0;
      margins.Bottom += margins.Bottom > 0 ? adj : 0;
      
      margins = new Margins(margins.Left, margins.Top, margins.Right, margins.Bottom);

      switch (alignment)
      {
        case Alignment.TopLeft:
        {
          rect = new Rectangle(area.Left + 0,
                               area.Top + 0,
                               margins.Left,
                               margins.Top);
          break;

        }
        case Alignment.TopCenter:
        {
          rect = new Rectangle(area.Left + margins.Left,
                               area.Top + 0,
                               area.Width - margins.Left - margins.Right,
                               margins.Top);
          break;

        }
        case Alignment.TopRight:
        {
          rect = new Rectangle(area.Left + area.Width - margins.Right,
                               area.Top + 0,
                               margins.Right,
                               margins.Top);
          break;

        }
        case Alignment.MiddleLeft:
        {
          rect = new Rectangle(area.Left + 0,
                               area.Top + margins.Top,
                               margins.Left,
                               area.Height - margins.Top - margins.Bottom);
          break;
        }
        case Alignment.MiddleCenter:
        {
          rect = new Rectangle(area.Left + margins.Left,
                               area.Top + margins.Top,
                               area.Width - margins.Left - margins.Right,
                               area.Height - margins.Top - margins.Bottom);
          break;
        }
        case Alignment.MiddleRight:
        {
          rect = new Rectangle(area.Left + area.Width - margins.Right,
                               area.Top + margins.Top,
                               margins.Right,
                               area.Height - margins.Top - margins.Bottom);
          break;
        }
        case Alignment.BottomLeft:
        {
          rect = new Rectangle(area.Left + 0,
                               area.Top + area.Height - margins.Bottom,
                               margins.Left,
                               margins.Bottom);
          break;
        }
        case Alignment.BottomCenter:
        {
          rect = new Rectangle(area.Left + margins.Left,
                               area.Top + area.Height - margins.Bottom,
                               area.Width - margins.Left - margins.Right,
                               margins.Bottom);
          break;
        }
        case Alignment.BottomRight:
        {
          rect = new Rectangle(area.Left + area.Width - margins.Right,
                               area.Top + area.Height - margins.Bottom,
                               margins.Right,
                               margins.Bottom);
          break;
        }
      }

      return rect;
    }
    ////////////////////////////////////////////////////////////////////////////    

    ////////////////////////////////////////////////////////////////////////////
    public void DrawGlyph(Glyph glyph, Rectangle rect)
    {           
      Size imageSize = new Size(glyph.Image.Width, glyph.Image.Height);
      
      if (!glyph.SourceRect.IsEmpty)
      {
        imageSize = new Size(glyph.SourceRect.Width, glyph.SourceRect.Height);
      }
      
      if (glyph.SizeMode == SizeMode.Centered)
      {
        rect = new Rectangle((rect.X + (rect.Width - imageSize.Width) / 2) + glyph.Offset.X,
                             (rect.Y + (rect.Height - imageSize.Height) / 2) + glyph.Offset.Y,
                             imageSize.Width,
                             imageSize.Height);
      }
      else if (glyph.SizeMode == SizeMode.Normal)
      {
        rect = new Rectangle(rect.X + glyph.Offset.X, rect.Y + glyph.Offset.Y, imageSize.Width, imageSize.Height);
      }
      else if (glyph.SizeMode == SizeMode.Auto)
      {
        rect = new Rectangle(rect.X + glyph.Offset.X, rect.Y + glyph.Offset.Y, imageSize.Width, imageSize.Height);
      }     
      
      if (glyph.SourceRect.IsEmpty)
      {
        Draw(glyph.Image, rect, glyph.Color);
      }
      else
      {
        Draw(glyph.Image, rect, glyph.SourceRect, glyph.Color);
      }  
    }
    ////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////
    public virtual void DrawLayer(Control control, SkinLayer layer, Rectangle rect)
    { 
      DrawLayer(control, layer, rect, control.ControlState);
    }
    ////////////////////////////////////////////////////////////////////////////   

    ////////////////////////////////////////////////////////////////////////////    
    public virtual void DrawLayer(Control control, SkinLayer layer, Rectangle rect, ControlState state)
    {
      Color c = Color.White;
      Color oc = Color.White;
      int i = 0;
      int oi = -1;
      SkinLayer l = layer;     

      if (state == ControlState.Hovered && (layer.States.Hovered.Index != -1))
      {
        c = l.States.Hovered.Color;
        i = l.States.Hovered.Index;

        if (l.States.Hovered.Overlay)
        {
          oc = l.Overlays.Hovered.Color;
          oi = l.Overlays.Hovered.Index;
        }
      }
      else if (state == ControlState.Focused || (control.Focused && state == ControlState.Hovered && layer.States.Hovered.Index == -1))
      {
        c = l.States.Focused.Color;
        i = l.States.Focused.Index;

        if (l.States.Focused.Overlay)
        {
          oc = l.Overlays.Focused.Color;
          oi = l.Overlays.Focused.Index;
        }
      }
      else if (state == ControlState.Pressed)
      {
        c = l.States.Pressed.Color;
        i = l.States.Pressed.Index;

        if (l.States.Pressed.Overlay)
        {
          oc = l.Overlays.Pressed.Color;
          oi = l.Overlays.Pressed.Index;
        }
      }
      else if (state == ControlState.Disabled)
      {
        c = l.States.Disabled.Color;
        i = l.States.Disabled.Index;

        if (l.States.Disabled.Overlay)
        {
          oc = l.Overlays.Disabled.Color;
          oi = l.Overlays.Disabled.Index;
        }
      }
      else
      {
        c = l.States.Enabled.Color;
        i = l.States.Enabled.Index;

        if (l.States.Enabled.Overlay)
        {
          oc = l.Overlays.Enabled.Color;
          oi = l.Overlays.Enabled.Index;
        }
      }

      if (control.Color != Control.UndefinedColor) c = control.Color * (control.Color.A / 255f);
      DrawLayer(l, rect, c, i);

      if (oi != -1)
      {       
        DrawLayer(l, rect, oc, oi);
      }
    }     
    ////////////////////////////////////////////////////////////////////////////   

    #endregion
    
  }
}